#ifndef __M_SESSION_H__
#define __M_SESSION_H__
#include "util.hpp"
#include <unordered_map>
#include <websocketpp/server.hpp>
#include <websocketpp/config/asio_no_tls.hpp>

typedef enum { UNLOGIN, LOGIN }ss_state;
class session
{
public:
    session(uint64_t ssid) : _ssid(ssid)
    {
        DLOG("SESSION %p 被创建！", this);
    }
    ~session()
    {
        DLOG("SESSION %p 被释放！", this);
    }

    uint64_t ssid() { return _ssid; }
    void set_user(uint64_t uid) {  _uid = uid; }
    void set_state(ss_state state) { _state = state; }
    uint64_t get_user() { return _uid; }
    bool is_login() { return (_state == LOGIN); }
    void set_timer(const wsserver_t::timer_ptr &tp) { _tp = tp; }
    wsserver_t::timer_ptr& get_timer() { return _tp; }
    
private:
    uint64_t _ssid;//标识符
    uint64_t _uid;//sesson对应的用户id
    ss_state _state;//用户状态
    wsserver_t::timer_ptr _tp;//session关联的定时器
};

#define SESSION_TIMEOUT 30000
#define SESSION_FOREVER -1
using session_ptr = std::shared_ptr<session>;
class session_manage
{
public:
    session_manage(wsserver_t *srv) : _next_ssid(1), _server(srv)
    {
        DLOG("session管理器初始化完毕！");
    }
    ~session_manage() { DLOG("session管理器即将销毁！"); }

    //创建session
    session_ptr create_session(uint64_t uid, ss_state state)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        session_ptr ssp(new session(_next_ssid));
        ssp->set_state(state);
        ssp->set_user(uid);
        _session.insert(std::make_pair(_next_ssid, ssp));
        _next_ssid++;
        return ssp;
    }

    //将ssp管理起来
    void append_session(const session_ptr &ssp)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _session.insert(std::make_pair(ssp->ssid(), ssp));
    }

    //通过ssid获取session
    session_ptr get_session_by_ssid(uint64_t ssid)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        auto it = _session.find(ssid);
        if (it == _session.end())
        {
            return session_ptr();
        }
        return it->second;
    }

    //删除session
    void remove_session(uint64_t ssid)
    {
        std::unique_lock<std::mutex> lock(_mutex);
        _session.erase(ssid);
    }

    //设置session到期时间
    void set_session_expire_time(uint64_t ssid, int ms)
    {
        //登录之后创建session，在指定时间内无通信之后需要删除
        //进入游戏大厅或游戏房间，session应该永久存在
        //退出游戏大厅或游戏房间，session应该重新被设置为临时，长时间无通信后删除
        session_ptr ssp = get_session_by_ssid(ssid);
        if (ssp.get() == nullptr)   return;

        wsserver_t::timer_ptr tp = ssp->get_timer();
        if (tp.get() == nullptr && ms == SESSION_FOREVER)
        {
            //定时器为空，且ms为SESSION_FOREVER表示当前session没有定时器且要设置为永久存在，这种情况下不需要做任何操作，直接返回
            return;
        }
        else if (tp.get() == nullptr && ms != SESSION_FOREVER)
        {
            //如果tp为空且ms不为SESSION_FOREVER，表示当前session没有定时器但需要设置一个过期时间
            wsserver_t::timer_ptr tmp_tp = _server->set_timer(ms, std::bind(&session_manage::remove_session, this, ssid));
            ssp->set_timer(tmp_tp);
        }
        else if (tp.get() != nullptr && ms == SESSION_FOREVER)
        {
            //如果tp不为空且ms为SESSION_FOREVER，表示当前session有定时器但现在要设置为永久存在
            tp->cancel();//取消当前定时器
            ssp->set_timer(wsserver_t::timer_ptr());//将定时器指针设置为空
            _server->set_timer(0, std::bind(&session_manage::append_session, this, ssp));
        }
        else if (tp.get() != nullptr && ms != SESSION_FOREVER)
        {
            //如果tp不为空且ms不为SESSION_FOREVER，表示当前session有定时器且要重新设置过期时间
            tp->cancel();
            ssp->set_timer(wsserver_t::timer_ptr());
            _server->set_timer(0, std::bind(&session_manage::append_session, this, ssp));
            wsserver_t::timer_ptr tmp_tp = _server->set_timer(ms, std::bind(&session_manage::remove_session, this, ssp->ssid()));
            ssp->set_timer(tmp_tp);
        }

    }
private:
    uint64_t _next_ssid;
    std::mutex _mutex;
    std::unordered_map<uint64_t, session_ptr> _session;
    wsserver_t *_server;
};
#endif